---
title: "Script for Shell Parsing Parameters"
categories:
- linux
- shell
tags:
---

<div id="content">
<blockquote>
<p>
<a href="https://oinkzwurgl.org/hacking/bash_cgi/">https://oinkzwurgl.org/hacking/bash_cgi/</a>
<a href="https://marc.waeckerlin.org/computer/blog/parsing_of_query_string_in_bash_cgi_scripts">https://marc.waeckerlin.org/computer/blog/parsing_of_query_string_in_bash_cgi_scripts</a>
</p>
</blockquote>
<div class="org-src-container">
<pre class="src src-sh"><span style="font-weight: bold; font-style: italic;">#</span><span style="font-weight: bold; font-style: italic;">!/bin/</span><span style="font-weight: bold;">bash</span>
<span style="font-weight: bold;">echo</span> -e <span style="font-style: italic;">"Content-type: text/html\n\n"</span>

<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">(internal) routine to store POST data</span>
<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">cgi_get_POST_vars</span>()
{
    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">only handle POST requests here</span>
    [ <span style="font-style: italic;">"$REQUEST_METHOD"</span> != <span style="font-style: italic;">"POST"</span> ] &amp;&amp; <span style="font-weight: bold;">return</span>

    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">save POST variables (only first time this is called)</span>
    [ ! -z <span style="font-style: italic;">"$QUERY_STRING_POST"</span> ] &amp;&amp; <span style="font-weight: bold;">return</span>

    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">skip empty content</span>
    [ -z <span style="font-style: italic;">"$CONTENT_LENGTH"</span> ] &amp;&amp; <span style="font-weight: bold;">return</span>

    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">check content type</span>
    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">FIXME: not sure if we could handle uploads with this..</span>
    [ <span style="font-style: italic;">"${CONTENT_TYPE}"</span> != <span style="font-style: italic;">"application/x-www-form-urlencoded"</span> ] &amp;&amp; <span style="font-style: italic;">\</span>
        <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"bash.cgi warning: you should probably use MIME type "</span><span style="font-style: italic;">\</span>
             <span style="font-style: italic;">"application/x-www-form-urlencoded!"</span> 1&gt;&amp;2

    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">convert multipart to urlencoded</span>
    <span style="font-weight: bold;">local</span> <span style="font-weight: bold; font-style: italic;">handlemultipart</span>=0 <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">enable to handle multipart/form-data (dangerous?)</span>
    <span style="font-weight: bold;">if</span> [ <span style="font-style: italic;">"$handlemultipart"</span> = <span style="font-style: italic;">"1"</span> -a <span style="font-style: italic;">"${CONTENT_TYPE:0:19}"</span> = <span style="font-style: italic;">"multipart/form-data"</span> ]; <span style="font-weight: bold;">then</span>
        <span style="font-weight: bold; font-style: italic;">boundary</span>=${<span style="font-weight: bold; font-style: italic;">CONTENT_TYPE</span>:30}
        <span style="font-weight: bold;">read</span> -N $<span style="font-weight: bold; font-style: italic;">CONTENT_LENGTH</span> RECEIVED_POST
        <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">FIXME: don't use awk, handle binary data (Content-Type: application/octet-stream)</span>
        <span style="font-weight: bold; font-style: italic;">QUERY_STRING_POST</span>=$(<span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"$RECEIVED_POST"</span> | awk -v <span style="font-weight: bold; font-style: italic;">b</span>=$<span style="font-weight: bold; font-style: italic;">boundary</span> <span style="font-style: italic;">'BEGIN { RS=b"\r\n"; FS="\r\n"; ORS="&amp;" }</span>
<span style="font-style: italic;">           $1 ~ /^Content-Disposition/ {gsub(/Content-Disposition: form-data; name=/, "", $1); gsub("\"", "", $1); print $1"="$3 }'</span>)

    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">take input string as is</span>
    <span style="font-weight: bold;">else</span>
        <span style="font-weight: bold;">read</span> -N $<span style="font-weight: bold; font-style: italic;">CONTENT_LENGTH</span> QUERY_STRING_POST
    <span style="font-weight: bold;">fi</span>

    <span style="font-weight: bold;">return</span>
}

<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">(internal) routine to decode urlencoded strings</span>
<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">cgi_decodevar</span>()
{
    [ $<span style="font-weight: bold; font-style: italic;">#</span> -ne 1 ] &amp;&amp; <span style="font-weight: bold;">return</span>
    <span style="font-weight: bold;">local</span> v t h
    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">replace all + with whitespace and append %%</span>
    <span style="font-weight: bold; font-style: italic;">t</span>=<span style="font-style: italic;">"${1//+/ }%%"</span>
    <span style="font-weight: bold;">while</span>{% raw %}  [ ${# {% endraw %}<span style="font-weight: bold; font-style: italic;">t</span>} -gt 0 -a <span style="font-style: italic;">"${t}"</span> != <span style="font-style: italic;">"%"</span> ]; <span style="font-weight: bold;">do</span>
        <span style="font-weight: bold; font-style: italic;">v</span>=<span style="font-style: italic;">"${v}${t%%\%*}"</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">digest up to the first %</span>
        <span style="font-weight: bold; font-style: italic;">t</span>=<span style="font-style: italic;">"${t#*%}"</span>       <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">remove digested part</span>
        <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">decode if there is anything to decode and if not at end of string</span>
        <span style="font-weight: bold;">if</span>{% raw %}  [ ${# {% endraw %}<span style="font-weight: bold; font-style: italic;">t</span>} -gt 0 -a <span style="font-style: italic;">"${t}"</span> != <span style="font-style: italic;">"%"</span> ]; <span style="font-weight: bold;">then</span>
            <span style="font-weight: bold; font-style: italic;">h</span>=${<span style="font-weight: bold; font-style: italic;">t</span>:0:2} <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">save first two chars</span>
            <span style="font-weight: bold; font-style: italic;">t</span>=<span style="font-style: italic;">"${t:2}"</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">remove these</span>
            <span style="font-weight: bold; font-style: italic;">v</span>=<span style="font-style: italic;">"${v}"</span><span style="font-weight: bold;">`echo -e \\\\x${h}`</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">convert hex to special char</span>
        <span style="font-weight: bold;">fi</span>
    <span style="font-weight: bold;">done</span>
    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">return decoded string</span>
    <span style="font-weight: bold;">echo</span> <span style="font-style: italic;">"${v}"</span>
    <span style="font-weight: bold;">return</span>
}

<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">routine to get variables from http requests</span>
<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">usage: cgi_getvars method varname1 [.. varnameN]</span>
<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">method is either GET or POST or BOTH</span>
<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">the magic varible name ALL gets everything</span>
<span style="font-weight: bold;">function</span> <span style="font-weight: bold;">cgi_getvars</span>()
{
    [ $<span style="font-weight: bold; font-style: italic;">#</span> -lt 2 ] &amp;&amp; <span style="font-weight: bold;">return</span>
    <span style="font-weight: bold;">local</span> q p k v s
    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">get query</span>
    <span style="font-weight: bold;">case</span> $<span style="font-weight: bold; font-style: italic;">1</span><span style="font-weight: bold;"> in</span>
        GET)
            [ ! -z <span style="font-style: italic;">"${QUERY_STRING}"</span> ] &amp;&amp; <span style="font-weight: bold; font-style: italic;">q</span>=<span style="font-style: italic;">"${QUERY_STRING}&amp;"</span>
            ;;
        POST)
            cgi_get_POST_vars
            [ ! -z <span style="font-style: italic;">"${QUERY_STRING_POST}"</span> ] &amp;&amp; <span style="font-weight: bold; font-style: italic;">q</span>=<span style="font-style: italic;">"${QUERY_STRING_POST}&amp;"</span>
            ;;
        BOTH)
            [ ! -z <span style="font-style: italic;">"${QUERY_STRING}"</span> ] &amp;&amp; <span style="font-weight: bold; font-style: italic;">q</span>=<span style="font-style: italic;">"${QUERY_STRING}&amp;"</span>
            cgi_get_POST_vars
            [ ! -z <span style="font-style: italic;">"${QUERY_STRING_POST}"</span> ] &amp;&amp; <span style="font-weight: bold; font-style: italic;">q</span>=<span style="font-style: italic;">"${q}${QUERY_STRING_POST}&amp;"</span>
            ;;
    <span style="font-weight: bold;">esac</span>
    <span style="font-weight: bold;">shift</span>
    <span style="font-weight: bold; font-style: italic;">s</span>=<span style="font-style: italic;">" $* "</span>
    <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">parse the query data</span>
    <span style="font-weight: bold;">while</span> [ ! -z <span style="font-style: italic;">"$q"</span> ]; <span style="font-weight: bold;">do</span>
        <span style="font-weight: bold; font-style: italic;">p</span>=<span style="font-style: italic;">"${q%%&amp;*}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">get first part of query string</span>
        <span style="font-weight: bold; font-style: italic;">k</span>=<span style="font-style: italic;">"${p%%=*}"</span>  <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">get the key (variable name) from it</span>
        <span style="font-weight: bold; font-style: italic;">v</span>=<span style="font-style: italic;">"${p#*=}"</span>   <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">get the value from it</span>
        <span style="font-weight: bold; font-style: italic;">q</span>=<span style="font-style: italic;">"${q#$p&amp;*}"</span> <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">strip first part from query string</span>
        <span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">decode and assign variable if requested</span>
        [ <span style="font-style: italic;">"$1"</span> = <span style="font-style: italic;">"ALL"</span> -o <span style="font-style: italic;">"${s/ $k /}"</span> != <span style="font-style: italic;">"$s"</span> ] &amp;&amp; <span style="font-style: italic;">\</span>
            <span style="font-weight: bold;">export</span> <span style="font-style: italic;">"$k"</span>=<span style="font-style: italic;">"`cgi_decodevar \"$v\"`"</span>
    <span style="font-weight: bold;">done</span>
    <span style="font-weight: bold;">return</span>
}

<span style="font-weight: bold; font-style: italic;"># </span><span style="font-weight: bold; font-style: italic;">register all GET and POST variables</span>
cgi_getvars BOTH ALL

cat &lt;&lt;EOF
<span style="font-weight: bold;">&lt;html&gt;</span>
<span style="font-weight: bold;">&lt;body&gt;</span>
<span style="font-weight: bold;">&lt;form action="?foo=${foo:=123}" method="POST" enctype="application/x-www-form-urlencoded"&gt;</span>
<span style="font-weight: bold;">bar: &lt;input type="text" name="bar" value="$bar"&gt;&lt;br/&gt;</span>
<span style="font-weight: bold;">foobar: &lt;textarea name="foobar"&gt;$foobar&lt;/textarea&gt;&lt;/br&gt;</span>
<span style="font-weight: bold;">&lt;input type="submit"&gt;</span>
<span style="font-weight: bold;">&lt;/form&gt;</span>

<span style="font-weight: bold;">&lt;pre&gt;foo=$foo&lt;/pre&gt;</span>
<span style="font-weight: bold;">&lt;pre&gt;bar=$bar&lt;/pre&gt;</span>
<span style="font-weight: bold;">&lt;pre&gt;foobar=$foobar&lt;/pre&gt;</span>

<span style="font-weight: bold;">&lt;/body&gt;</span>
<span style="font-weight: bold;">&lt;/html&gt;</span>
<span style="font-weight: bold;">EOF</span>
</pre>
</div>
</div>
<div class="status" id="postamble">
<p class="author">Author: amo</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
